package subpub

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type SubscriberFunc func(topic string, args ...interface{})

type subscriberNode struct {
	callback SubscriberFunc
	prev     *subscriberNode
	next     *subscriberNode
	topic    string
	valid    bool
}

type subscriberList struct {
	head  *subscriberNode
	tail  *subscriberNode
	count int // 订阅者计数器
	mu    sync.RWMutex
}

type SubPub struct {
	mu     sync.RWMutex
	topics map[string]*subscriberList
}

func NewSubPub() *SubPub {
	return &SubPub{
		topics: make(map[string]*subscriberList),
	}
}

func (s *SubPub) StartAutoCleanup(ctx context.Context, interval time.Duration) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			s.CleanupEmptyTopics()
		case <-ctx.Done():
			return
		}
	}

}

// CleanupEmptyTopics 注意：必须先释放 RLock() 再加 Lock()，否则会导致死锁
func (s *SubPub) CleanupEmptyTopics() int {
	s.mu.Lock()
	defer s.mu.Unlock()

	removedCount := 0
	toRemove := make([]string, 0)

	// 遍历主题时加读锁检查订阅数
	for topic, list := range s.topics {
		list.mu.RLock()
		count := list.count
		list.mu.RUnlock()

		if count == 0 {
			toRemove = append(toRemove, topic)
		}
	}

	// 批量删除空主题（此时s.mu已加锁，s.topics不会被并发修改）
	for _, topic := range toRemove {
		list := s.topics[topic] // 无需检查exists，因为s.mu已锁定，topic必然存在

		// 最终确认：加写锁确保删除前没有新订阅
		list.mu.Lock()
		if list.count == 0 {
			delete(s.topics, topic)
			removedCount++
		}
		list.mu.Unlock()
	}

	return removedCount
}

func (s *SubPub) Subscribe(topic string, callback SubscriberFunc) interface{} {
	if callback == nil {
		return nil // 拒绝空回调
	}

	s.mu.Lock()
	if _, exists := s.topics[topic]; !exists {
		s.topics[topic] = &subscriberList{}
	}
	list := s.topics[topic]
	s.mu.Unlock()

	node := &subscriberNode{
		callback: callback,
		topic:    topic,
		valid:    true,
	}

	list.mu.Lock()
	defer list.mu.Unlock()

	// 添加节点到链表
	if list.tail == nil {
		list.head = node
		list.tail = node
	} else {
		list.tail.next = node
		node.prev = list.tail
		list.tail = node
	}
	list.count++ // 增加计数器

	return node
}

func (s *SubPub) GetTopicsCount() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return len(s.topics)
}

func (s *SubPub) Unsubscribe(handle interface{}) error {
	node, ok := handle.(*subscriberNode)
	// 严格检查节点有效性
	if !ok || node == nil || !node.valid {
		return fmt.Errorf("invalid handle")
	}

	s.mu.RLock()
	list, exists := s.topics[node.topic]
	s.mu.RUnlock()

	if !exists {
		return fmt.Errorf("invalid handle topic is not found")
	}

	list.mu.Lock()
	defer list.mu.Unlock()

	// 再次检查有效性，防止并发情况下的重复取消
	if !node.valid {
		return fmt.Errorf("invalid handle")
	}

	// 移除节点
	if node.prev != nil {
		node.prev.next = node.next
	} else {
		list.head = node.next
	}
	if node.next != nil {
		node.next.prev = node.prev
	} else {
		list.tail = node.prev
	}

	// 标记节点无效
	node.valid = false
	node.prev = nil
	node.next = nil
	node.callback = nil

	// 只有在计数器为正数时才减少，从根源防止负数
	list.count--

	if list.count < 0 {
		return fmt.Errorf("invalid nodes")
	}

	return nil
}

func (s *SubPub) Publish(topic string, args ...interface{}) (n int) {
	s.mu.RLock()
	list, exists := s.topics[topic]
	s.mu.RUnlock()

	if !exists {
		return 0
	}

	list.mu.RLock()
	var nodes []*subscriberNode
	for node := list.head; node != nil; node = node.next {
		if node.valid {
			nodes = append(nodes, node)
		}
	}
	list.mu.RUnlock()

	for _, node := range nodes {
		if node.valid && node.callback != nil {
			n++
			node.callback(topic, args...)
		}
	}

	return n
}

func (s *SubPub) GetSubscriberCount(topic string) int {
	s.mu.RLock()
	list, exists := s.topics[topic]
	s.mu.RUnlock()

	if !exists {
		return 0
	}

	list.mu.RLock()
	defer list.mu.RUnlock()
	return list.count
}
